package com.freemalll.merchant.utils;

import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.annotation.TableField;
import com.freemalll.merchant.common.CommonEnum;
import com.freemalll.merchant.common.CompareField;
import com.freemalll.merchant.domain.dto.ColumnDTO;
import com.freemalll.merchant.mapper.common.CommonMapper;
import com.freemalll.merchant.service.MerMerchantService;
import com.freemalll.merchant.service.coopManagement.MerAssetManageService;
import com.freemalll.merchant.service.impl.MerParamsServiceImpl;
import io.swagger.v3.oas.annotations.media.Schema;
import jodd.util.StringUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;


@Component
public class HistoryDiffUtils {

    @Autowired
    private CommonMapper commonMapper;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private MerMerchantService merMerchantService;
    @Autowired
    private MerAssetManageService merAssetManageService;

    /**
     * 将带有 @ColumnName 注解的字段提取为 "中文名: 值" 的字符串拼接形式
     *
     * @param dto DTO 对象
     * @return 拼接后的字符串
     */
    public String getAnnotatedFieldsWithValues(Object dto) {
        if (dto == null) {
            return "";
        }

        List<String> result = new ArrayList<>();

        Field[] fields = dto.getClass().getDeclaredFields();

        for (Field field : fields) {
            field.setAccessible(true); // 允许访问私有字段
            CompareField compareField = field.getAnnotation(CompareField.class);
            Schema schema = field.getAnnotation(Schema.class);

            // 跳过没有 CompareField 注解的字段
            if (compareField == null) {
                continue;
            }

            // 跳过特殊字段
            if (compareField.skip()) {
                continue;
            }
            String columnName = schema != null ? schema.description() : "";

            try {
                Object value = field.get(dto);
                // 如果值为 null，则跳过该字段
                if (value == null) {
                    continue;
                }

                String displayValue = "";

                // 处理 BigDecimal 格式化，避免显示为科学计数法
                if (value instanceof BigDecimal) {
                    value = ((BigDecimal) value).toPlainString();
                }
                // 处理布尔类型
                if (value instanceof Boolean) {
                    value = (Boolean) value ? "启用" : "禁用";
                }

                // 检查字段名并从枚举转码
                if ("payment_preference".equals(compareField.value())) {
                    displayValue = CommonEnum.PaymentPreferenceEnum.getDescByCode((String) value);
                } else if ("card_type".equals(compareField.value())|| "payment_type".equals(compareField.value())) {
                    displayValue = CommonEnum.CardTypeEnum.getDescByCode((String) value);
                }

                // 如果字段是特殊处理的类型之一，使用转码后的值，否则使用原始值
                String finalValue = ("payment_preference".equals(compareField.value()) || "card_type".equals(compareField.value())||
                        "payment_type".equals(compareField.value()))
                        ? displayValue
                        : (value != null ? value.toString() : "");

                result.add(columnName + "：" + finalValue);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }

        return String.join(", ", result);
    }

    public <T> Map<String,List<String>> getDiffValue(T newDto, T oldDto) {
        List<ColumnDTO> columnDTOList = new ArrayList<>();
        Map<String,List<String>> resultMap = new HashMap<>(2);

        try {
            if (compareTwoObj(newDto, oldDto)) {
                compareFieldsRecursively(newDto, oldDto, "", columnDTOList);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (CollectionUtils.isEmpty(columnDTOList)) {
            return resultMap;
        }

        List<String> oldList = new ArrayList<>();
        List<String> newList = new ArrayList<>();

        for (ColumnDTO d : columnDTOList) {
            if (!d.isDiffStatus() || StringUtils.isBlank(d.getName())) {
                continue;
            }
            if (StringUtils.isNotBlank(d.getOldValue())) {
                oldList.add(d.getName() + ": " + d.getOldValue());
            }
            if (StringUtils.isNotBlank(d.getValue())) {
                newList.add(d.getName() + ": " + d.getValue());
            }
        }

        resultMap.put("old", oldList);
        resultMap.put("new", newList);
        return resultMap;
    }

    /**
     * 递归比较字段
     */
    public  <T> void compareFieldsRecursively(T newDto, T oldDto, String prefix, List<ColumnDTO> result) throws Exception {
        Class<?> clazz = newDto.getClass();
        Field[] fields = clazz.getDeclaredFields();

        for (Field field : fields) {
            field.setAccessible(true);

            CompareField compareField = field.getAnnotation(CompareField.class);
            Schema schema = field.getAnnotation(Schema.class);

            // 跳过没有 CompareField 注解的字段
            if (compareField == null) {
                continue;
            }

            // 跳过特殊字段
            if (compareField.skip()) {
                continue;
            }

            String fieldName = field.getName();
            String methodName = buildGetterMethodName(fieldName);
            Method method = clazz.getDeclaredMethod(methodName, (Class<?>[]) null);

            Object newValue = method.invoke(newDto);
            Object oldValue = method.invoke(oldDto);

            // 获取字段描述
            String fieldDescription = schema != null ? schema.description() : "";

            // 如果字段是 DTO 类型，递归比较
            if (isDtoType(field.getType())) {
                if (newValue != null && oldValue != null) {
                    compareFieldsRecursively(newValue, oldValue, prefix + "." + fieldDescription, result);
                }
                continue;
            }

            // 基本类型字段直接比较
            boolean isDifferent = !compareTwoValue(newValue, oldValue);
            if (!isDifferent) {
                continue;
            }

            ColumnDTO columnDTO = new ColumnDTO();
            columnDTO.setName(prefix.isEmpty() ? fieldDescription : prefix + "." + fieldDescription);
            columnDTO.setValue(getEmptyString(Optional.ofNullable(newValue).map(Object::toString).orElse(""), field));
            columnDTO.setOldValue(getEmptyString(Optional.ofNullable(oldValue).map(Object::toString).orElse(""), field));
            columnDTO.setDiffStatus(true);
            result.add(columnDTO);
        }
    }

    /**
     * 判断是否为 DTO 类型（非基础类型）
     */
    private boolean isDtoType(Class<?> type) {
        return !(type.isPrimitive() ||
                type.equals(String.class) ||
                Number.class.isAssignableFrom(type) ||
                type.equals(Boolean.class) ||
                type.equals(Character.class));
    }

    /**
     * 构建 getter 方法名
     */
    private String buildGetterMethodName(String name) throws Exception {
        if (name == null || name.isEmpty()) {
            throw new Exception("字段名不能为空");
        }
        return "get" + name.substring(0, 1).toUpperCase() + name.substring(1);
    }

//    public <T> Map<String,List<String>> getDiffValue(T newDto, T oldDto) {
//        List<ColumnDTO> columnDTOList = new ArrayList<>();
//        Map<String,List<String>> resultMap = new HashMap<>(2);
//        try {
//            if (compareTwoObj(newDto, oldDto)) {
//                Class<?> newClass = newDto.getClass();
//                Field[] newFields = newClass.getDeclaredFields();
//                for (Field field : newFields) {
//                    //字段上没有贴注解的跳过比对
//                    TableField annotation = field.getAnnotation(TableField.class);
//
//                    ApiModelProperty coiumnComment = field.getAnnotation(ApiModelProperty.class);
//
//                    if (annotation == null) {
//                        continue;
//                    }
//                    String name = field.getName();
//                    field.setAccessible(true);
//                    ColumnDTO columnDTO = new ColumnDTO();
//                    String getMethodName;
//                    //拼装Node节点对象
//                    if (name != null && name != "" && name.length() > 1) {
//                        getMethodName = "get" + name.substring(0, 1).toUpperCase() + name.substring(1);
//                    } else if (name.length() == 1) {
//                        getMethodName = "get" + name.toUpperCase();
//                    } else {
//                        throw new Exception("方法不能为空");
//                    }
//                    Method method = newClass.getDeclaredMethod(getMethodName, null);
//                    //新旧值对比
//                    if (!compareTwoValue(method.invoke(newDto), method.invoke(oldDto))) {
//                        columnDTO.setDiffStatus(true);
//                    }
//
//                    //需要跳过比较的列
//                    if(annotation.value().equals("rate_id")||annotation.value().equals("template_code")){
//                        continue ;
//                    }
//
//                    columnDTO.setValue(getEmptyString(Optional.ofNullable(method.invoke(newDto)) // 包装可能为 null 的值
//                            .map(Object::toString) // 非 null 时转换为字符串
//                            .orElse(""),annotation));
//                    columnDTO.setName(Optional.ofNullable(coiumnComment.value()) // 包装可能为 null 的值
//                            .map(Object::toString) // 非 null 时转换为字符串
//                            .orElse(""));
//                    columnDTO.setOldValue(getEmptyString(Optional.ofNullable(method.invoke(oldDto)) // 包装可能为 null 的值
//                            .map(Object::toString) // 非 null 时转换为字符串
//                            .orElse(""), annotation));
//                    columnDTOList.add(columnDTO);
//                }
//            }
//        } catch (Exception e) {
//            e.getMessage();
//        }
//        if (CollectionUtils.isEmpty(columnDTOList)) {
//            return resultMap;
//        }
//        List<String> oldList = new ArrayList<>();
//        List<String> newList = new ArrayList<>();
//        for (ColumnDTO d : columnDTOList) {
//            if (!d.isDiffStatus() || StringUtils.isBlank(d.getName())) {
//                continue;
//            }
//            if (StringUtils.isNotBlank(d.getOldValue())) {
//                oldList.add(d.getName() + ": " + d.getOldValue());
//            }
//            if (StringUtils.isNotBlank(d.getValue())) {
//                newList.add(d.getName() + ": " + d.getValue());
//            }
//        }
//        resultMap.put("old", oldList);
//        resultMap.put("new", newList);
//        return resultMap;
//    }


    /**
     * 比较两个类是否属于同一个Class
     */
    private <T> boolean compareTwoObj(T newDto, T oldDto) throws Exception {
        //null判断都不为空
        if (Objects.isNull(newDto) || Objects.isNull(oldDto)) {
            throw new Exception("传入对象不能为空");
        }
        if (newDto.getClass() == oldDto.getClass()) {
            return true;
        }
        return false;
    }

    /**
     * 比较两个相同类对象的相同属性值是否相同
     */
    private boolean compareTwoValue(Object newValue, Object oldValue) {
        // Objects.equals 会处理 null 情况：两者均为 null 时返回 true，否则比较值
        if (newValue instanceof BigDecimal && oldValue instanceof BigDecimal) {
            return ((BigDecimal) newValue).compareTo((BigDecimal) oldValue) == 0;
        }
        return Objects.equals(newValue, oldValue);
    }

    /**
     * 比较两个相同类对象的相同属性值是否相同
     */
    private String getEmptyString(String value, Field field) {
        if (StringUtil.isBlank(value)) return "";
        if ("true".equals(value)) return "是";
        if ("false".equals(value)) return "否";

        CompareField compareField = field.getAnnotation(CompareField.class);
        TableField tableField = field.getAnnotation(TableField.class);
        String fieldName = compareField != null ? compareField.value() : (tableField != null ? tableField.value() : "");
        String fieldLower = fieldName.toLowerCase();

        // 直接映射的枚举/参数类型
        Map<String, Function<String, String>> fieldValueConverters = new HashMap<>();
        fieldValueConverters.put("rental_type", CommonEnum.RentalTypeEnum::getDescByCode);
        fieldValueConverters.put("card_type", CommonEnum.CardTypeEnum::getDescByCode);
        fieldValueConverters.put("payment_preference", CommonEnum.PaymentPreferenceEnum::getDescByCode);
        fieldValueConverters.put("interest_and_fee_model", CommonEnum.InterestAndFeeTypeEnum::getDescByCode);
        fieldValueConverters.put("interest_and_fee_detail_model", CommonEnum.InterestAndFeeTypeEnum::getDescByCode);
        fieldValueConverters.put("school_type", CommonEnum.schoolType::getDescByCode);
        fieldValueConverters.put("payment_type", CommonEnum.CardTypeEnum::getDescByCode);

        if (fieldValueConverters.containsKey(fieldName)) {
            return fieldValueConverters.get(fieldName).apply(value);
        }

        // 特殊业务逻辑
        switch (fieldName) {
            case "store_type":
                return CommonEnum.storeType.getStoreTypeByCode(value).getDescription();
            case "apply_type":
                return CommonEnum.applyType.getApplyTypeByCode(value).getDescription();
            case "brand_type":
                return CommonEnum.brandType.getBrandTypeByCode(value).getDescription();
            case "source_id": {
                // 资方
                return Optional.ofNullable(merAssetManageService.getById(value)).map(obj -> "(" + obj.getSourceName() + ")").orElse("");
            }
            case "related_mer_id":
                return merMerchantService.getById(value).getMerName();
            case "traffic_merchant":
                return "1".equals(value) ? "是" : "否";
            case "mer_model":
                if ("1".equals(value)) return "直客";
                if ("2".equals(value)) return "渠道";
                break;
        }

        // 省市区自动查中文名
        if (fieldLower.contains("province") || fieldLower.contains("city") || fieldLower.contains("county") || fieldLower.contains("country")) {
            return getZoneNameByCode(value);
        }

        // 参数转码
        Set<String> paramFields = new HashSet<>(Arrays.asList(
                "first_recommended_platform", "competitive_product_types", "online_platform", "project_list",
                "advertisement", "scene_parent_category", "scene_category"
        ));
        if (paramFields.contains(fieldName)) {
            MerParamsServiceImpl service = SpringUtil.getBean(MerParamsServiceImpl.class);
            return service.translateParamKeys(value);
        }

        return value;
    }

    /**
     * 根据行政区划编码查中文名，带redis缓存
     */
    private String getZoneNameByCode(String code) {
        if (StringUtils.isBlank(code)) {
            return "";
        }
        String cacheKey = "zone_name:" + code;
        try {
            Object cache = redisUtil.get(cacheKey);
            if (cache != null) {
                return cache.toString();
            }
            String name = commonMapper.selectValueByCode(code);
            if (name != null) {
                // 缓存一天
                redisUtil.set(cacheKey, name, 24 * 60 * 60L);
                return name;
            }
            return code;
        } catch (Exception e) {
            return code;
        }
    }

}
